<template>
  <q-layout
    view="hHh Lpr lff"
    container
    style="min-height: calc(100vh - 32px); background-color: #1e1f22"
    group="layout-group"
    @drop="onDrop($event, jobId)"
  >
    <q-drawer dark show-if-above side="right" :width="200" bordered>
      <q-scroll-area class="fit" style="border-color: #aaaaaa; background-color: #2b2d30">
        <SideBar :inputs="inputs" :gateways="gateways" :outputs="outputs" />
      </q-scroll-area>
    </q-drawer>
    <q-page-container>
      <q-page style="height: calc(100vh - 32px)">
        <q-inner-loading :showing="panelShow">
          <q-spinner-gears size="50px" color="primary" />
        </q-inner-loading>
        <VueFlow
          min-zoom="0.1"
          max-zoom="2"
          @dragover="onDragOver"
          @dragleave="onDragLeave"
          class="full-height"
          v-if="!panelShow"
        >
          <Controls>
            <ControlButton title="Reset Transform" @click="showTerminal">
              <svg width="16" height="16" viewBox="0 0 24 24">
                <path
                  d="M20 19V7H4v12h16m0-16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16m-7 14v-2h5v2h-5m-3.42-4L5.57 9H8.4l3.3 3.3c.39.39.39 1.03 0 1.42L8.42 17H5.59l3.99-4Z"
                />
              </svg>
            </ControlButton>
          </Controls>
          <MiniMap pannable zoomable nodeColor="#333338" />
          <Panel position="top-center">
            <q-btn-group outline>
              <q-btn
                outline
                color="white"
                label="执行"
                @click="runJob"
                v-if="!jobDetail.isRunning"
                icon="play_arrow"
              />
              <q-btn
                outline
                color="white"
                label="停止"
                @click="stopJob"
                v-if="jobDetail.isRunning"
                icon="stop"
              />
            </q-btn-group>
          </Panel>
          <DropzoneBackground
            :style="{
              backgroundColor: isDragOver ? '#e7f3ff' : 'transparent',
              transition: 'background-color 0.2s ease',
            }"
          >
            <p v-if="isDragOver">Drop here</p>
          </DropzoneBackground>
          <template #node-input="specialNodeProps">
            <DefNode
              :ref="specialNodeProps.id"
              v-bind="specialNodeProps"
              :with-input="false"
              :with-output="true"
              :with-input-handle="false"
            />
          </template>
          <!-- bind your custom node type to a component by using slots, slot names are always `node-<type>` -->
          <template #node-output="specialNodeProps">
            <DefNode
              :ref="specialNodeProps.id"
              v-bind="specialNodeProps"
              :with-input="true"
              :with-output="false"
              :with-input-handle="true"
            />
          </template>
          <!-- bind your custom node type to a component by using slots, slot names are always `node-<type>` -->
          <template #node-gateway="specialNodeProps">
            <!--            @reSortHandles="-->
            <!--            (handles) => {-->
            <!--            const node = { ...specialNodeProps }-->
            <!--            node.data.handles = handles-->
            <!--            saveNode(node)-->
            <!--            }"-->
            <DefNode
              :ref="specialNodeProps.id"
              v-bind="specialNodeProps"
              :with-input="true"
              :with-output="true"
              :with-input-handle="false"
            />
          </template>

          <!-- bind your custom edge type to a component by using slots, slot names are always `edge-<type>` -->
          <template #edge-special="specialEdgeProps">
            <SpecialEdge v-bind="specialEdgeProps" :ref="specialEdgeProps.id" />
          </template>
        </VueFlow>
        <q-dialog
          v-model="terminalShow"
          persistent
          full-width
          position="bottom"
          transition-show="slide-up"
          transition-hide="slide-down"
        >
          <q-card dark>
            <q-bar>
              <q-space/>
              <q-btn dense flat icon="close" v-close-popup>
                <q-tooltip class="bg-white text-primary">Close</q-tooltip>
              </q-btn>
            </q-bar>
            <q-card-section style="max-height: 50vh" class="q-pt-none scroll">
              <devops-xterm ref="devopsXterm" :jobId="jobId" />
            </q-card-section>
          </q-card>
        </q-dialog>
      </q-page>
    </q-page-container>
  </q-layout>
</template>
<script setup>
import { Panel, useVueFlow, VueFlow } from '@vue-flow/core'
import { MiniMap } from '@vue-flow/minimap'
import useDragAndDrop from './components/useDnD.js'
import SpecialEdge from './components/SpecialEdge.vue'
import SideBar from './components/SideBar.vue'
import DropzoneBackground from './components/DropzoneBackground.vue'
import axios from 'axios'
import { usePluginStore } from 'stores/plugin-store.js'
import { getCurrentInstance, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import DefNode from 'pages/mgmt/job/model/nodes/DefNode.vue'
import { ControlButton, Controls } from '@vue-flow/controls'
import DevopsXterm from 'components/DevopsXterm.vue'


const {
  onConnect,
  addEdges,
  setNodes,
  setEdges,
  onNodeDragStop,
  onNodesChange,
  onEdgesChange,
  applyNodeChanges,
  findNode
} = useVueFlow()
const props = defineProps(['jobId', 'isRunning'])
const store = usePluginStore()
const { setPlugins } = store
const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop()

// Reactive state
const panelShow = ref(true)
const jobDetail = ref({})

const inputs = ref([])
const filters = ref([])
const gateways = ref([])
const outputs = ref([])
const { proxy } = getCurrentInstance()

onConnect((newEdge) => {
  console.log('newEdge', newEdge)
  axios
    .post('/transflow/node/link', {
      sourceId: newEdge.source,
      targetId: newEdge.target,
      sourceHandle: newEdge.sourceHandle,
      targetHandle: newEdge.targetHandle,
    })
    .then((response) => {
      addEdges({ ...response.data })
    })
})
onNodeDragStop(({ node: draggedNode }) => {
  proxy.$refs[draggedNode.id]?.saveNode()
})
onNodesChange(async (changes) => {
  for (const change of changes) {
    // 删除节点
    if (change.type === 'remove') {
      await axios.post('/transflow/node/delete', {
        id: change.id,
      })
    }
    // 节点失去焦点 时 触发更新
    if (change.type === 'select' && !change.selected) {
      const node = findNode(change.id)
      proxy.$refs[node.id]?.saveNode()
    }
  }
  onEdgesChange(async (changes) => {
    for (const change of changes) {
      // 删除连接
      if (change.type === 'remove') {
        await axios.post('/transflow/node/unlink', {
          id: change.id,
        })
      }
    }
  })
  applyNodeChanges(changes)
})

const queryForPlugins = () => {
  panelShow.value = true
  axios.get('/transflow/plugins/list').then((response) => {
    setPlugins(response.data)
    inputs.value = response.data.filter((plugin) => plugin.type === 'input')
    outputs.value = response.data.filter((plugin) => plugin.type === 'output')
    filters.value = response.data.filter((plugin) => plugin.type === 'filter')
    gateways.value = response.data.filter((plugin) => plugin.type === 'gateway')
    panelShow.value = false
  })
}
const reloadData = (newJobId) => {
  axios.get('/transflow/node/allForDraw?jobId=' + newJobId).then((response) => {
    setNodes(response.data.nodes)
    setEdges(response.data.edges)
  })
}
const getJobDetail = (newJobId) => {
  axios.get('/transflow/job/detail?jobId=' + newJobId).then((response) => {
    jobDetail.value = response.data
  })
}
const runJob = () => {
  axios.post('/transflow/job/run', { id: props.jobId }).then(() => {
    getJobDetail(props.jobId)
  })
}
const stopJob = () => {
  axios.post('/transflow/job/stop', { id: props.jobId }).then(() => {
    getJobDetail(props.jobId)
  })
}
const createWebsocket = () => {
  const socket = new WebSocket('ws://' + window.location.host + '/transflow/event/' + props.jobId)
  socket.addEventListener('open', () => {
    console.log('WebSocket已连接')
  })
  socket.addEventListener('message', (event) => {
    const data = JSON.parse(event.data)
    switch (data.type) {
      case 'edge': {
        const edgeId = data.value
        proxy.$refs[edgeId].animateDot()
      }
    }
  })
  socket.addEventListener('close', () => {
    console.log('WebSocket连接已关闭')
  })
  socket.addEventListener('error', (error) => {
    console.error('WebSocket发生错误:', error)
  })
}

const terminalShow = ref(false)
const showTerminal = function(){
  terminalShow.value = true
}

onMounted(() => {
  queryForPlugins()
})
onBeforeUnmount(() => {
  // if (socket) {
  //   socket.close()
  // }
})

watch(
  () => props.jobId,
  async (newVal) => {
    if (!newVal) return
    console.log('Job ID changed:', newVal)
    getJobDetail(newVal)
    reloadData(newVal)
    createWebsocket()
  },
  { immediate: true },
)
</script>
<style></style>
